﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace DmxLib
{
    /// <summary>
    /// artnet 发送类  按帧率发循环发送
    /// </summary>
    public class ArtNetSend : IDmxSend
    {
        private System.Net.IPEndPoint remoteIpendPoint;
        private System.Net.IPEndPoint localIPEndPoint;
        private int frame;
        private byte[] sendData;
        private System.Timers.Timer timer;
        private Socket socket;
        private int universe;
        /// <summary>
        /// artnet 发送类  按帧率发循环发送
        /// </summary>
        /// <param name="artnetIP">artnet 地址</param>
        /// <param name="localIPEndPoint">绑定本机的IP地址</param>
        /// <param name="universe">artnet域</param>
        /// <param name="frame">帧率 默认30</param>
        public ArtNetSend(System.Net.IPAddress artnetIP, System.Net.IPEndPoint localIPEndPoint, int universe, int frame = 30)
        {
            if (universe < 0 || universe > 16)
                throw new ArgumentException("universe必须大于0小于16");
            this.universe = universe;
            sendData = new byte[512];
            remoteIpendPoint = new System.Net.IPEndPoint(artnetIP, 6454);
            this.frame = frame;
            this.localIPEndPoint = localIPEndPoint;
        }

        private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {


            //for (int i = 0; i < UniverseCount; i++)

            //    sendData.Add(new byte[512]);
            try
            {
                byte[] d = GetArtDmx(sendData, universe);
                socket.SendTo(d, remoteIpendPoint);
            }
            catch (Exception)
            {


            }

            // }

        }
        /// <summary>
        /// 更新缓存的数据
        /// </summary>
        /// <param name="dm512">长度为0-512 值为0-255的数据包</param>
        public void UpdateData(byte[] dmxval)
        {
            //if (dm512 == null || universe>UniverseCount||universe<0)
            //    return;
            //for (int i = 0; i < dm512.Length&&i<512; i++)
            //{
            //    sendData[universe][i] = dm512[i];
            //}
            if (dmxval == null)
                throw new ArgumentNullException("dmxval is null");
            for (int i = 0; i < dmxval.Length && i < 512; i++)
            {
                sendData[i] = dmxval[i];
            }
        }
        /// <summary>
        /// 按索引更新  索引0-511
        /// </summary>
        /// <param name="index">索引</param>
        /// <param name="value">值</param>
        public void UpdateData(int index, byte value)
        {

            if (index >= 0 & index < 512)
                sendData[index] = value;
        }
        /// <summary>
        /// 按起始位置更新数据 超出不更新
        /// </summary>
        /// <param name="startIndex"> 缓存数组的起始位置</param>
        /// <param name="value">数据索引</param>
        public void UpdateData(int startIndex, byte[] dmxval)
        {
            if (dmxval == null)
                throw new ArgumentNullException("dmxval is null");
            if (startIndex >= 0 & startIndex < 512)
            {
                for (int i = startIndex, j = 0; j < dmxval.Length && i < 512; i++, j++)
                {
                    sendData[i] = dmxval[j];
                }
            }
        }
        /// <summary>
        /// 按起始位置结束更新数据 超出不更新 更新目标数组的起始结束位置
        /// </summary>
        /// <param name="value">需要更新的数组</param>
        /// <param name="startIndex">缓存数组的起始位置</param>
        /// <param name="endIndex">需要更新原数组的长度</param>
        public void UpdateData(byte[] dmxval, int startIndex, int count)
        {
            if (dmxval == null)
                throw new ArgumentNullException("dmxval is null");
            if (dmxval.Length < count)
                throw new ArgumentException("dmxval 数组长度比count小");
            if (startIndex >= 0 & startIndex < 512)
            {
                for (int i = startIndex, j = 0; i < dmxval.Length && i < 512 && j < count; i++, j++)
                {
                    sendData[i] = dmxval[i];
                }
            }
        }
        private bool isStart = false;

        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 是否启动
        /// </summary>
        public bool IsStart
        {
            private set
            {
                isStart = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsStart"));
            }
            get => isStart;
        }
        /// <summary>
        /// 启动 按帧率发送数据
        /// </summary>
        public void Start()
        {
            if (IsStart)
                return;
            //Stop();
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            socket.Bind(localIPEndPoint);
            socket.EnableBroadcast = false;
            timer = new System.Timers.Timer();
            timer.Elapsed += Timer_Elapsed;
            timer.Interval = 1000 / frame;
            timer.Start();
            IsStart = true;
        }
        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            if (!IsStart)
                return;
            if (timer != null)
            {
                timer.Stop();
                timer.Dispose();
                timer = null;

            }
            IsStart = false;
        }
        ~ArtNetSend()
        {
            if (socket != null)
            {
                socket.Close();
            }
            if (timer != null)
            {
                timer.Stop();
                timer.Dispose();
                timer = null;

            }
        }
        public void Dispose()
        {
            Stop();
        }

        #region 组织一个Artnet数据包
        /// <summary>
        /// 组织一个Artnet数据包
        /// </summary>
        /// <param name="buffer_dmx">数据</param>
        /// <param name="universe">域</param>
        /// <returns></returns>
        public byte[] GetArtDmx(byte[] buffer_dmx, int universe)
        {
            char[] ArtNetHead = new char[8];
            ArtNetHead[0] = 'A';
            ArtNetHead[1] = 'r';
            ArtNetHead[2] = 't';
            ArtNetHead[3] = '-';
            ArtNetHead[4] = 'N';
            ArtNetHead[5] = 'e';
            ArtNetHead[6] = 't';

            int art_net_header_size = 17;
            int DMX_Universe = universe;//universe is from 0 to 15, subnet is not used
            int number_of_channels = 512; //512 for 512 channels, MAX=512
            short OpOutput = 0x5000;//output
            //byte[] buffer_dmx = new byte[number_of_channels]; //buffer used for DMX data
            byte[] ArtDmxBuffer = new byte[(art_net_header_size + number_of_channels) + 8 + 1];

            for (int i = 0; i < 7; i++)
            {
                ArtDmxBuffer[i] = System.Text.Encoding.Default.GetBytes(ArtNetHead)[i];
            }
            ArtDmxBuffer[8] = (byte)OpOutput;
            ArtDmxBuffer[9] = (byte)(OpOutput >> 8);
            //protocole
            ArtDmxBuffer[10] = 0;
            ArtDmxBuffer[11] = 14;
            //sequence
            ArtDmxBuffer[12] = 0;
            //physical 
            ArtDmxBuffer[13] = 0;

            // universe 
            ArtDmxBuffer[14] = (byte)DMX_Universe;//or 0
            ArtDmxBuffer[15] = (byte)(DMX_Universe >> 8);
            //data length
            ArtDmxBuffer[16] = (byte)(number_of_channels >> 8);
            ArtDmxBuffer[17] = (byte)(number_of_channels);


            for (int t = 0; t < 512; t++)
            {
                ArtDmxBuffer[t + art_net_header_size + 1] = buffer_dmx[t];
            }
            return ArtDmxBuffer;
        }
        #endregion
    }
}
